/**/
package cz.vutbr.fit.VYPe.team18.VYPe11;

/* --------------------------Usercode Section------------------------ */
import java_cup.runtime.*;
import cz.vutbr.fit.VYPe.team18.VYPe11.exception.LexicalException;
      
%%
   
/* -----------------Options and Declarations Section----------------- */
%class Scanner
%line
%column
%cup
%initthrow LexicalException
%scanerror LexicalException
   
%{   
    StringBuffer string = new StringBuffer();

    /* To create a new java_cup.runtime.Symbol with information about
       the current token, the token will have no value in this
       case. */
    private Symbol symbol(int type) {
        return new Symbol(type, yyline, yycolumn);
    }
    
    /* Also creates a new java_cup.runtime.Symbol with information
       about the current token, but this object has a value. */
    private Symbol symbol(int type, Object value) {
        return new Symbol(type, yyline, yycolumn, value);
    }
%}   

InputCharacter = [^\r\n]

/* A line terminator is a \r (carriage return), \n (line feed), or \r\n. */
LineTerminator = \r|\n|\r\n
   
/* White space */
WhiteSpace     = {LineTerminator} | [ \t\f]
   
/* Numeric literal */
integer_lit = 0 | [1-9][0-9]*
   
/* string and character literals */
StringCharacter = [^\r\n\"\\]
SingleCharacter = [^\r\n\'\\]

/* A identifier */
identifier = [A-Za-z_][A-Za-z_0-9]*

/* comments */
Comment = {TraditionalComment} | {EndOfLineComment}
TraditionalComment = "/*" [^*] ~"*/" | "/*" "*"+ "/"
EndOfLineComment = "//" {InputCharacter}* {LineTerminator}?

%state STRINGLITERAL, CHARLITERAL

%%
/* ------------------------Lexical Rules Section---------------------- */
   
<YYINITIAL> {
   /* keywords */
  "break"                        { return symbol(sym.BREAK); }
  "char"                         { return symbol(sym.CHAR); }
  "continue"                     { return symbol(sym.CONTINUE); }
  "else"                         { return symbol(sym.ELSE); }
  "int"                          { return symbol(sym.INT); }
  "if"                           { return symbol(sym.IF); }
  "short"                        { return symbol(sym.SHORT); }
  "string"			 { return symbol(sym.STRING); }
  "return"                       { return symbol(sym.RETURN); }
  "void"                         { return symbol(sym.VOID); }
  "while"                        { return symbol(sym.WHILE); }

  /* separators */
  "("                            { return symbol(sym.LPAREN); }
  ")"                            { return symbol(sym.RPAREN); }
  "{"                            { return symbol(sym.LBRACE); }
  "}"                            { return symbol(sym.RBRACE); }
  "["                            { return symbol(sym.LBRACK); }
  "]"                            { return symbol(sym.RBRACK); }
  ";"                            { return symbol(sym.SEMICOLON); }
  ","                            { return symbol(sym.COMMA); }

  /* operators */
  "="                            { return symbol(sym.EQ); }
  ">"                            { return symbol(sym.GT); }
  "<"                            { return symbol(sym.LT); }
  "!"                            { return symbol(sym.NOT); }
  "~"                            { return symbol(sym.COMP); }
  "=="                           { return symbol(sym.EQEQ); }
  "<="                           { return symbol(sym.LTEQ); }
  ">="                           { return symbol(sym.GTEQ); }
  "!="                           { return symbol(sym.NOTEQ); }
  "&&"                           { return symbol(sym.ANDAND); }
  "||"                           { return symbol(sym.OROR); }
  "+"                            { return symbol(sym.PLUS); }
  "-"                            { return symbol(sym.MINUS); }
  "*"                            { return symbol(sym.MULT); }
  "/"                            { return symbol(sym.DIV); }
  "%"                            { return symbol(sym.MOD); }
  "&"                            { return symbol(sym.AND); }
  "|"                            { return symbol(sym.OR); }
   
  /* string literal */
  \"                             { yybegin(STRINGLITERAL); string.setLength(0); }

  /* character literal */
  \'                             { yybegin(CHARLITERAL); }
    
  /* Integer number */
  {integer_lit}      { 
			 Integer number = new Integer(yytext());
			 return (number>Short.MAX_VALUE) ? symbol(sym.INTLITERAL, number) : symbol(sym.SHORTLITERAL, new Short(yytext()));
  	       }
   
  /* White spaces and comments */
  {WhiteSpace}       { }
  {Comment}	     { }

  /* Identifikator */
  {identifier}       { return symbol(sym.ID, yytext()); }
}

<STRINGLITERAL> {
  \"                             { yybegin(YYINITIAL); return symbol(sym.STRINGLITERAL, string.toString()); }
  
  {StringCharacter}+             { string.append( yytext() ); }
  
  /* escape sequences */
  "\\n"                          { string.append( '\n' ); }
  "\\t"                          { string.append( '\t' ); }
  "\\\""                         { string.append( '\"' ); }
  "\\'"                          { string.append( '\'' ); }
  "\\\\"                         { string.append( '\\' ); }
  
  /* error cases */
  \\.                            { throw new LexicalException("Illegal escape sequence \""+yytext()+"\""); }
  {LineTerminator}               { throw new LexicalException("Unterminated string at end of line"); }
}

<CHARLITERAL> {
  {SingleCharacter}\'            { yybegin(YYINITIAL); return symbol(sym.CHARLITERAL, new Character(yytext().charAt(0))); }
  
  /* escape sequences */
  "\\t"\'                        { yybegin(YYINITIAL); return symbol(sym.CHARLITERAL, new Character('\t'));}
  "\\n"\'                        { yybegin(YYINITIAL); return symbol(sym.CHARLITERAL, new Character('\n'));}
  "\\\""\'                       { yybegin(YYINITIAL); return symbol(sym.CHARLITERAL, new Character('\"'));}
  "\\'"\'                        { yybegin(YYINITIAL); return symbol(sym.CHARLITERAL, new Character('\''));}
  "\\\\"\'                       { yybegin(YYINITIAL); return symbol(sym.CHARLITERAL, new Character('\\')); }
  "\\0"\'                        { yybegin(YYINITIAL); return symbol(sym.CHARLITERAL, new Character('\0')); }
  
  /* error cases */
  \\.                            { throw new LexicalException("Illegal escape sequence \""+yytext()+"\""); }
  {LineTerminator}               { throw new LexicalException("Unterminated character literal at end of line"); }
}

/* No token was found for the input so through an error.  Print out an
   Illegal character message with the illegal character that was found. */
[^]                    { throw new LexicalException("Illegal character <"+yytext()+">"); }
